//
// Created by DELL on 2022/4/19.
//
#pragma once

#include "../Utils.h"
#include "../VulkanDefine.h"

BEGIN_NS_VULKAN

class SwapChain
{
public:
    static constexpr int MAX_FRAMES_IN_FLIGHT = 2;

    ~SwapChain();
    SwapChain(const SwapChain&) = delete;
    SwapChain operator=(const SwapChain&) = delete;

    static SwapChainRef create(const DeviceRef& device, const GLWindowRef& window);
    void recreate();

    VkFramebuffer getFrameBuffer(int index) { return frameBuffers[index]; }
    VkRenderPass getRenderPass() { return renderPass; }
    VkImageView getImageView(int index) { return imageViews[index]; }
    size_t imageCount() { return images.size(); }
    VkFormat getImageFormat() { return imageFormat; }
    VkFormat getDepthFormat() { return depthFormat; }

    const VkExtent2D& getExtent() const { return extent; }
    uint32_t getWidth() const { return extent.width; }
    uint32_t getHeight() const { return extent.height; }

    VkResult acquireNextImage(uint32_t& imageIndex);
    VkResult submitCommandBuffers(const VkCommandBuffer* buffers, uint32_t imageIndex);

    bool compareSwapFormats(const SwapChainRef& other) const
    {
        return other->imageFormat == imageFormat && other->depthFormat == depthFormat;
    }


private:
    SwapChain(DeviceRef device, const GLWindowRef& window);

    void init(const GLWindowRef& window);
    void createSwapChain(VkSwapchainKHR oldSwapChain, const GLWindowRef& window);
    void createImageViews();
    void createDepthResources();
    void createRenderPass();
    void createFrameBuffers();
    void createSyncObjects();


    void cleanFrameBuffer();
    VkSurfaceFormatKHR chooseSwapSurfaceFormat(
        const std::vector<VkSurfaceFormatKHR>& availableFormats);
    VkPresentModeKHR chooseSwapPresentMode(
        const std::vector<VkPresentModeKHR>& availablePresentModes);
    VkExtent2D chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, const GLWindowRef& window);

    VkFormat imageFormat{};
    VkFormat depthFormat{};
    VkExtent2D extent{};

    std::vector<VkFramebuffer> frameBuffers{};
    VkRenderPass renderPass{};

    std::vector<VkImage> depthImages{};
    std::vector<VkDeviceMemory> depthImageMemorys{};
    std::vector<VkImageView> depthImageViews{};
    std::vector<VkImage> images{};
    std::vector<VkImageView> imageViews{};

    DeviceRef device{};
    GLWindowRef glWindow{};

    VkSwapchainKHR swapChain{};

    std::vector<VkSemaphore> imageAvailableSemaphores{};
    std::vector<VkSemaphore> renderFinishedSemaphores{};
    std::vector<VkFence> inFlightFences{};
    std::vector<VkFence> imagesInFlight{};
    size_t currentFrame = 0;

};

END_NS_VULKAN